package logo;

import java.util.Hashtable;
import java.util.Vector;

class Commands extends Vector<ICommand>
{
	private static final long serialVersionUID = 1L;

	void addCommand(ICommand cmd)
	{
		add(cmd);
	}
	
	Parameters getParametersForFunction(String name)
	{
		for (ICommand cmd: this)
		{
			if (cmd instanceof CommandFunction)
			{
				Parameters result = ((CommandFunction) cmd)._commands.getParametersForFunction(name);
				if (result != null)
					return result;
			}
			if (cmd instanceof CommandLoop)
			{
				Parameters result = ((CommandLoop) cmd)._commands.getParametersForFunction(name);
				if (result != null)
					return result;
			}
			if (cmd instanceof CommandCall)
			{
				CommandCall call = (CommandCall)cmd;
				if (call._name.equals(name))
					return call._params;
			}
		}
		return null;
	}
	
	Commands getCommandsForFunction(String name)
	{
		for (ICommand cmd: this)
		{
			if (cmd instanceof CommandFunction)
			{
				Commands result = ((CommandFunction) cmd)._commands.getCommandsForFunction(name);
				if (result != null)
					return result;
			}
			if (cmd instanceof CommandFunction)
			{
				CommandFunction fn = (CommandFunction)cmd;
				if (fn._name.equals(name))
					return fn._commands;
			}
		}
		return null;
	}
}

interface ICommand {
	public void action(Turtle t, LogoPanel panel, String name);
}

abstract class BaseCommand implements ICommand
{
	private String _paramname;
	
	protected BaseCommand()
	{
		_paramname = null;
	}
	
	protected BaseCommand(String paramname)
	{
		_paramname = paramname;
	}
	
	protected Object getValue(String functionname, Object defvalue)
	{
		if (_paramname!= null)
		{
			Debug.log("Looking for param called " + _paramname);
			Parameters params = Logo.getLogo()._parser._commands.getParametersForFunction(functionname);
			if (params == null)
			{
				Debug.error("Param not found");
				return null;
			}
			return params.get(_paramname);
		}
		return defvalue;
	}
}

class CommandUp implements ICommand
{
	@Override
	public void action(Turtle t, LogoPanel panel, String name) {
		Debug.log("Action: Up");
		t.up();
	}
}

class CommandDown implements ICommand
{
	@Override
	public void action(Turtle t, LogoPanel panel, String name) {
		Debug.log("Action: Down");
		t.down();
	}
}

class CommandForward extends BaseCommand
{
	int length;

	public CommandForward(int len)
	{
		length = len;
	}

	public CommandForward(String paramname)
	{
		super(paramname);
	}
	
	@Override
	public void action(Turtle t, LogoPanel panel, String functionname) {
		Debug.log("Action: Forward");
		t.forward(Integer.valueOf(getValue(functionname, length).toString()));
	}
}

class CommandLeft extends BaseCommand
{
	int degrees;

	public CommandLeft(int deg)
	{
		degrees = deg;
	}

	public CommandLeft(String name)
	{
		super(name);
	}

	@Override
	public void action(Turtle t, LogoPanel panel, String functionname) {
		Debug.log("Action: Left " + degrees + " degrees");
		t.left((Integer)getValue(functionname, degrees));
	}
}

class CommandRight extends BaseCommand
{
	int degrees;

	public CommandRight(int deg)
	{
		degrees = deg;
	}

	public CommandRight(String name)
	{
		super(name);
	}

	@Override
	public void action(Turtle t, LogoPanel panel, String functionname) {
		Debug.log("Action: Right " + degrees + " degrees");
		t.right((Integer)getValue(functionname, degrees));
	}
}

class CommandLoop implements ICommand
{
	Commands _commands;
	int _count;
	
	public CommandLoop(int count)
	{
		_commands = new Commands();
		_count = count;
	}
	
	public void addSubCommand(ICommand sub)
	{
		_commands.add(sub);
	}
	
	@Override
	public void action(Turtle t, LogoPanel panel, String name)
	{
		Debug.log("Action: Loop");
		for (int i = 0; i < _count; ++i)
			Logo.getLogo().action(t, panel, _commands, name);
	}
}

class CommandWait extends BaseCommand
{
	int _wait;
	
	public CommandWait(int ms)
	{
		_wait = ms;
	}
	
	@Override
	public void action(Turtle t, LogoPanel panel, String functionname) {
		Debug.log("Action: Wait");
		Logo.sleep((Integer)getValue(functionname, _wait));
	}
}

class CommandReset implements ICommand
{
	@Override
	public void action(Turtle t, LogoPanel panel, String name) {
		Debug.log("Action: Reset");
		t.reset();
		panel.clearPanel();
	}
}

class Parameters extends Hashtable<String, Object>
{
	private static final long serialVersionUID = 1L;
	public void addParameter(String name, Object value)
	{
		put(name, value);
	}
}

class CommandFunction implements ICommand
{
	String _name;
	Commands _commands;
	
	public CommandFunction(String name)
	{
		_name = name;
		_commands = new Commands();
	}
	
	public void addCommand(ICommand cmd)
	{
		_commands.addCommand(cmd);
	}
	
	@Override
	public void action(Turtle t, LogoPanel panel, String name) {
		Debug.log("Action: Function ["+ _name +"] definition");
	}
}

class CommandCall implements ICommand
{
	String _name;
	Parameters _params;
	
	public CommandCall(String name)
	{
		_name = name;
		_params = new Parameters();
	}

	public void addParameter(String name, int value)
	{
		_params.addParameter(name, value);
	}
	
	
	@Override
	public void action(Turtle t, LogoPanel panel, String name) {
		Debug.log("Action: Call Function " + _name);
		
		Commands cmd = Logo.getLogo()._parser._commands.getCommandsForFunction(_name);
		if (cmd == null)
		{
			Debug.error("Function not found");
			return;
		}
		Logo.getLogo().action(t, panel, cmd, _name);
	}
}
